---
title: Gesture options
section: Reference
order: 2
---

import Code from './code/'
import UseGesture from './code/rug'
import Specs from './code/Specs'
import { CodeSnippet, TabPanel } from './CodeSnippet'

# Gesture options

&zwnj;<UseGesture /> offers different options to configure the gestures.

Some options are shared to the way <UseGesture /> behaves while some other options can be configured per gesture.

<carbon-ad />

## Structure of the config object

Depending on whether you use gesture-specific hooks or if you use the `useGesture` hook or `Gesture` class, you'll need to structure the config option object differently.

<CodeSnippet>
  <TabPanel>

```js
// when you use a gesture-specific hook
useDrag((state) => doSomethingWith(state), { ...sharedOptions, ...dragOptions })

// when you use the useGesture hook
useGesture(
  {
    onDrag: (state) => doSomethingWith(state),
    onPinch: (state) => doSomethingWith(state)
    // ...
  },
  {
    // global options such as `target`
    ...sharedOptions,
    // gesture specific options
    drag: dragOptions,
    wheel: wheelOptions,
    pinch: pinchOptions,
    scroll: scrollOptions,
    hover: hoverOptions
  }
)
```

</TabPanel>
<TabPanel>

```js
// when you use a gesture-specific class
new DragGesture(
  element,
  state => doSomethingWith(state),
  { ...sharedOptions, ...dragOptions }
)

// when you use the Gesture class
new Gesture(element, {
  onDrag: state => doSomethingWith(state),
  onPinch: state => doSomethingWith(state),
  // ...
  {
    // global options such as `target`
    ...sharedOptions,
    // gesture specific options
    drag: dragOptions,
    wheel: wheelOptions,
    pinch: pinchOptions,
    scroll: scrollOptions,
    wheel: wheelOptions,
    hover: hoverOptions,
  }
})
```

  </TabPanel>
</CodeSnippet>

### Shared options

Shared options deal with how <UseGesture /> will set event listeners.

| Option                          | Description                                                                                                     |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| [`target`](#target-react-only)  | Lets you specify a dom node or React ref you want to attach the gesture to.                                     |
| [`eventOptions`](#eventoptions) | Lets you customize if you want events to be passive or captured.                                                |
| [`window`](#window)             | Lets you specify which window element the gesture should bind events to (only relevant for the `drag` gesture). |
| [`enabled`](#enabled)           | When set to `false` none of your handlers will be fired.                                                        |

### Gesture options

Here are all options that can be applied to gestures.

> All options are not available to all gestures. In the table below **xy** designates coordinates-based gestures: drag, move, wheel and scroll.

| Options                                   |                                           Gestures                                            | Description                                                                                                                                                                                          |
| ----------------------------------------- | :-------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`enabled`](#enabled)                     |                                            **all**                                            | Whether the gesture is enabled.                                                                                                                                                                      |
| [`eventOptions`](#eventoptions)           | Lets you customize if you want events to be passive or captured. Overrides the shared option. |
| [`from`](#from)                           |                                            **all**                                            | The initial position `offset` should start from.                                                                                                                                                     |
| [`threshold`](#threshold)                 |                                            **all**                                            | The handler will fire only when the gesture displacement is greater than the threshold.                                                                                                              |
| [`preventDefault`](#preventdefault)       |                                            **all**                                            | Will `preventDefault` all events triggered by the handler.                                                                                                                                           |
| [`triggerAllEvents`](#triggerallevents)   |                                            **all**                                            | Forces the handler to fire even for non intentional displacement (ignores the `threshold`). In that case, the `intentional` attribute from state will remain `false` until the threshold is reached. |
| [`axis`](#axis)                           |                                            **all**                                            | Your handler will only trigger if a movement is detected on the specified axis.                                                                                                                      |
| [`axisThreshold`](#axisthreshold)         |                                            **xy**                                             | Axes are calculated based on a threshold. For drag, thresholds are specified per device type.                                                                                                        |
| [`bounds`](#bounds)                       |                                            **xy**                                             | Limits the gesture `offset` to the specified bounds.                                                                                                                                                 |
| [`scaleBounds`](#scalebounds)             |                                           **pinch**                                           | Limits the scale `offset` to the specified bounds.                                                                                                                                                   |
| [`angleBounds`](#anglebounds)             |                                           **pinch**                                           | Limits the angle `offset` to the specified bounds.                                                                                                                                                   |
| [`modifierKey`](#modifierkey)             |                                           **pinch**                                           | The modifier key that triggers a scale when wheeling. Defaults to `'ctrlKey'`. Can be `null`.                                                                                                        |
| `pinchOnWheel`                            |                                           **pinch**                                           | If `false`, pinching with the wheel will be disabled.                                                                                                                                                |
| [`rubberband`](#rubberband)               |                                            **all**                                            | The elasticity coefficient of the gesture when going out of bounds. When set to `true`, the elasticity coefficient will be defaulted to `0.15`                                                       |
| [`transform`](#transform)                 |                                            **all**                                            | A function that you can use to transform pointer values. Useful to map your screen coordinates to custom space coordinates such as a canvas.                                                         |
| [`filterTaps`](#filtertaps)               |                                           **drag**                                            | If `true`, the component won't trigger your drag logic if the user just clicked on the component.                                                                                                    |
| [`tapsThreshold`](#tapsthreshold)         |                                           **drag**                                            | Customize the displacement triggering taps when using the `filterTaps` option. Default is `3`.                                                                                                       |
| [`preventScroll`](#preventscroll)         |                                           **drag**                                            | If set, the drag will be triggered after the duration of the delay (in `ms`) and will prevent window scrolling. When set to `true`, `preventScroll` is defaulted to `250ms`.                         |
| [`preventScrollAxis`](#preventscrollaxis) |                                           **drag**                                            | If set, the drag will allow scrolling in the direction of the axis/axes unless the preventScroll duration has elapsed. Defaults to only 'y'.                                                         |
| [`pointer.touch`](#pointertouch)          |                                        **drag,pinch**                                         | If `true`, drag and pinch will use touch events on touch-enabled devices. [Read more below](#pointertouch).                                                                                          |
| [`pointer.capture`](#pointercapture)      |                                           **drag**                                            | If `false`, drag will not use `setPointerCapture` and attach `pointerMove` events to the window. [Read more below](#pointercapture).                                                                 |
| `pointer.mouse`                           |                                           **drag**                                            | If `true`, drag will use mouse event listeners instead of pointer listeners when possible.                                                                                                           |
| [`pointer.buttons`](#pointerbuttons)      |                                           **drag**                                            | Combination of buttons that triggers the drag gesture. [Read more below](#pointerbuttons).                                                                                                           |
| [`pointer.lock`](#pointerlock)            |                                           **drag**                                            | If `true`, the pointer will enter pointer lock mode when drag starts, and exit pointer lock when drag ends. [Read more below](#pointerlock).                                                         |
| [`pointer.keys`](#pointerkeys)            |                                           **drag**                                            | By default, the drag gesture can be triggered by arrow keys when the draggable element is focused. Setting `keys` to `false` won't add keyboard event listeners.                                     |
| [`delay`](#delay)                         |                                           **drag**                                            | If set, the handler will be delayed for the duration of the delay (in `ms`) — or if the user starts moving. When set to `true`, `delay` is defaulted to `180ms`.                                     |
| [`swipe.distance`](#swipedistance)        |                                           **drag**                                            | The minimum distance per axis (in `pixels`) the drag gesture needs to travel to trigger a swipe.                                                                                                     |
| [`swipe.velocity`](#swipevelocity)        |                                           **drag**                                            | The minimum velocity per axis (in `pixels / ms`) the drag gesture needs to reach before the pointer is released.                                                                                     |
| [`swipe.duration`](#swipeduration)        |                                           **drag**                                            | The maximum duration in milliseconds that a swipe is detected.                                                                                                                                       |
| `keyboardDisplacement`                    |                                           **drag**                                            | The distance (in `pixels`) emulated by arrow keys. Default is `10`.                                                                                                                                  |
| `mouseOnly`                               |                                        **hover, move**                                        | Set to `false` if you want your `hover` or `move` handlers to be triggered on non-mouse events. This is a useful option in case you want to perform logic on touch-enabled devices.                  |

## Options explained

### angleBounds

<Specs
  types={['AngleBounds: { min?: number, max?: number }', '(gestureState) => AngleBounds']}
  defaultValue="{ min: -Infinity, max: Infinity }"
/>

See also [`scaleBounds`](#scalebounds).

### axis

#### xy gestures

<Specs types={['x', 'y', 'lock', 'undefined']} defaultValue="undefined" />

`axis` makes it easy to constrain the user gesture to a specific axis.

<Code id="Axis" />

```jsx highlight={3}
function AxisExample() {
  const [{ x }, api] = useSpring(() => ({ x: 0 }))
  const bind = useDrag(({ down, movement: [mx] }) => api.start({ x: down ? mx : 0 }), { axis: 'x' })
  return <animated.div {...bind()} style={{ x }} />
}
```

From the code below it isn't obvious to understand why `axis` might be useful, since in any case the `y` movement isn't part of the logic.

But in reality `axis` does slightly more than just locking the gesture direction: if it detects that the user intent is to move the component in a different direction, it will stop firing the gesture handler. Here is an example to show the difference.

<Code id="Axis2" />

The component above can only move along the `x` axis. But try dragging and moving the component on the vertical axis. Without the `axis` option, you should notice the component movement will slightly jiggle horizontally because your movement won't be perfectly vertical.

#### 'lock' option (pinch as well)

`axis: 'lock'` allows you to lock the movement of the gesture once a direction has been detected. In other words, if the user starts moving horizontally, the gesture will be locked on the `x` axis.

<Code id="LockAxis" />

```jsx highlight={3-8}
function LockAxisExample() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(
    ({ down, movement: [mx, my] }) => {
      api.start({ x: down ? mx : 0, y: down ? my : 0, immediate: down })
    },
    { axis: 'lock' }
  )
  return <animated.div {...bind()} style={{ x, y }} />
}
```

### axisThreshold

A gesture axis is determined whenever x-axis and y-axis displacements reach a threshold.

#### xy gestures (except for drag)

<Specs types="number" defaultValue={0} />

For non-drag xy gestures, that threshold is always a number, which defaults to `0`.

#### drag

<Specs types="{ mouse: number, pen: number, touch: number }" defaultValue="{ mouse: 0, pen: 8, touch: 0 }" />

Drag logic is the same, but you must specify the threshold for a specific device. Since pen is much more sensitive than other devices, the default threshold has been empirically set to `8`.

### bounds

<Specs
  types={['Bounds: { top?: number, bottom?: number, left?: number, right?: number }', '(gestureState) => Bounds']}
  defaultValue="{ top: -Infinity, bottom: Infinity, left: -Infinity, right: Infinity }"
/>

If you want to set constraints to the user gesture, then you should use the `bounds` option. In that case, **both** the gesture `movement` and `offset` will be clamped to the specified `bounds`. `bounds` will be defaulted to `Infinity` when not set.

<Code id="Bounds" disableOverlay />

```jsx highlight={3-6}
function BoundsExample() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ down, offset: [ox, oy] }) => api.start({ x: ox, y: oy, immediate: down }), {
    bounds: { left: -100, right: 100, top: -50, bottom: 50 }
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> `scaleBounds` and `angleBounds` serve the same purpose as `bounds` for the `pinch` gesture, in a `{min,max}` format.

#### Drag bounds

<Specs
  types={['DragBounds: Bounds | HTMLElement | React.RefObject<HTMLElement>', '(gestureState) => DragBounds']}
  defaultValue="{ top: -Infinity, bottom: Infinity, left: -Infinity, right: Infinity }"
/>

Since v10 and for the drag gesture only, `bounds` can be a React ref or an HTMLElement, in which case the dragged element will be constrained to the element bounds (calculated with `getBoundingClientRect`).

### enabled

<Specs types="boolean" defaultValue="true" />

Whether the gesture is enabled.

### eventOptions

<Specs types="{capture: boolean, passive: bolean}" defaultValue="{capture: false, passive: true}" />

When `eventOptions.capture` is set to `true`, [events will be captured](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).

`eventOptions.passive` sets whether events are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).

> React warning: if you want events not to be passive, you will need to attach events directly to a node using `target` because of [the way React handles events](https://github.com/facebook/react/issues/6436)

### delay

<Specs gestures={['drag']} types={['boolean', 'number']} defaultValue="0" />

`delay` delays the drag gesture for the amount of milliseconds you specify. This might be useful if you don't want your logic to fire right away. The below example has a `delay` set to `1000`. Try clicking on the square without moving your mouse.

<Code id="Delay" />

Note that if the the pointer is moved by the user, the drag gesture will fire immediately without waiting for the `delay`.

```jsx highlight={3-7}
function DelayExample() {
  const [{ x, y, scale }, api] = useSpring(() => ({ x: 0, y: 0, scale: 1 }))
  const bind = useDrag(
    ({ down, movement: [mx, my] }) => api.start({ x: down ? mx : 0, y: down ? my : 0, scale: down ? 1.2 : 1 }),
    { delay: 1000 }
  )
  return <animated.div {...bind()} style={{ x, y, scale }} />
}
```

> When using `delay` and `threshold` options at the same time, the drag will start after the delay no matter what.

### filterTaps

<Specs gestures={['drag']} types="boolean" defaultValue="false" />

Making a draggable component tappable or clickable can be tricky: differenciating a click from a drag is not always trivial. When you set `filterTaps` to `true`, the [`tap`](/docs/state/#tap) state attribute will be `true` on release if the total displacement is inferior to `3 pixels` while `down` will remain `false` all along.

<Code id="FilterTaps" />

```jsx highlight={3-5,7-9}
function FilterTapsExample() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(
    ({ down, movement: [mx, my], tap }) => {
      if (tap) alert('tap!')
      api.start({ x: down ? mx : 0, y: down ? my : 0 })
    },
    { filterTaps: true }
  )
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> If you still want your handler to be triggered for non intentional displacement, this is where the `triggerAllEvents` config option and the `intentional` state attribute become useful.

> If you want to configure the minimum displacement for the tap to be triggered, have a look at the [tapsThreshold option](#tapsThreshold)

### from

<Specs types={['vector', '(gestureState) => vector']} defaultValue="[0,0]" />

Everytime a gesture starts, the `offset` state attribute starts with its previous value. But in some cases, you might want to start `offset` from an initial position that is external to your logic[^1].

[^1]: If you're used to <UseGesture />, this was the most common usecase for `memo`.

Let's take a tangible example: say that a draggable component turns back to its initial position **slowly**. In the meantime, the draggable component should still be **interruptible** at any moment. In that case, you can use `from` to set the position of the component **at the moment** the user drags it to the value of the spring.

<Code id="From" />

Drag the blue square and **before it goes back to its origin** drag it again. If you've unticked the checkbox, you'll notice that the square goes back to its origin instead of moving from where you've dragged it: that's because `offset` is by default reset to `[0,0]`.

The code below shows how the example works:

```jsx highlight={3-7}
function InitialExample() {
  const [{ x }, api] = useSpring(() => ({ x: 0 }))
  const bind = useDrag(
    ({ down, offset: [ox] }) => api.start({ x: down ? ox : 0, immediate: down, config: { duration: 3000 } }),
    { from: () => [x.get(), 0] }
  )
  return <animated.div {...bind()} style={{ x }} />
}
```

> Unless your initial position is static or depends on `state`, make sure you use a function rather than a static array.

### modifierKey

<Specs
  gestures={['pinch']}
  types={[`'ctrlKey'`, `'altKey'`, `'metaKey'`, `Array<'ctrlKey' | 'altKey' | 'metaKey'>`, 'null']}
  defaultValue={`'ctrlKey'`}
/>

This option lets you set the modifier key that triggers a scale gesture when using wheel inside the `onPinch` handler.

When `null`, pinching will be triggered using wheel _without_ the need of pressing a modifier key.

You can also pass an array of modifier keys to trigger the pinch gesture.

### pointer.buttons

<Specs gestures={['drag']} types={['number', 'number[]']} defaultValue="1" />

Most of the time you'll want the drag gesture to start when the `left / main` button of your device is pressed. You can change that behavior by submitting a [buttons combination](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons) that matches one or several buttons to be pressed at once in order for the drag gesture to start.

You can also submit an array with different combinations. In that case, any combination included in that array will trigger the drag.

```js
const dragConfig = { pointer: { buttons: [1, 2, 4] } }
```

> If you'd like **any** buttons combination to trigger the drag, you can just pass `-1` to the config option.

### pointer.capture

<Specs gestures={['drag']} types={'boolean'} defaultValue="true" />

By default, drag uses [`setPointerCapture`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture) to track the pointer movement. When a pointer is captured by a target, it won't trigger any listener from another target (even a CSS `:hover`). Most of the time this is fine, but in some situations, you may want to drag an element and still receive events from another target.

<Code id="CaptureFalse" />

In the example above, the blue dot listens for hover events: when the pink dot is being dragged, it will attach to it. You'll notice that when `pointer.capture` is set to `true`, you won't be able to connect the dots. That's because the blue dot doesn't get pointer events when the pink dot capture the events. Setting `pointer.capture` to false solves this problem.

> Note that this example doesn't work on mobile and is just here to illustrate the option. If you'd want to actually do this in a way that works on mobile, you'd probably have to use `document.elementAtPoint`. [Look at this sandbox](https://codesandbox.io/s/github/pmndrs/use-gesture/tree/main/demo/src/sandboxes/dots-connect).

### pointer.keys

<Specs gestures={['drag']} types="boolean" defaultValue="true" />

By default, the drag gesture is accessible, meaning you can control the drag of an element with arrow keys. The ` shiftKey` modifier will make the drag 10x faster, the `altKey` will make the drag 10x slower.

If you set `keys` to `false`, your drag handler won't respond to keyboard events.

### pointer.lock

<Specs gestures={['drag']} types={'boolean'} defaultValue="false" />

Set `lock` to `true` and the drag gesture will [`requestPointerLock`](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestPointerLock) when the drag starts and `exitPointerLock` when the drag gesture ends. This feature is only relevant on non-touch devices.

<Code id="PointerTrue" />

In the example above, the cursor will be hidden when the drag starts and the square will "loop" horizontally and vertically inside its parent element.

### pointer.touch

<Specs gestures={['drag', 'pinch']} types={'boolean'} defaultValue="false" />

Most gestures, drag included, use [pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events). This works well in 99 situations in 100, but pointer events get canceled on touch devices when the user starts scrolling. Usually this is what you actually want, and the browser does it for you. But in some situations you may want the drag to persist while scrolling. In that case you'll need to indicate <UseGesture /> to use touch events, which aren't canceled on scroll.

### preventDefault

<Specs types="boolean" defaultValue="false" />

Will run `event.cancelable && event.preventDefault()` on all events triggered by the handler. Can be useful when dragging links or images.

<Code id="PreventDefault" />

```jsx highlight={4-5}
function PreventDefault() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ offset: [x, y] }) => api.start({ x, y }), {
    preventDefault: true,
    filterTaps: true
  })
  return <animated.a href="https://github.com/pmndrs/use-gesture" {...bind()} style={{ x, y }} />
}
```

> Don't forget to use the [`filterTaps`](#filtertaps) option to prevent the link from opening unintentionally at the end of the gesture.

### preventScroll

<Specs gestures={['drag']} types={'boolean'} defaultValue="false" />

**This is an experimental feature, relevant for mobile devices**.

`touch-action: none` is a common CSS property that you'll set on draggable items so that scroll doesn't interfere with the drag behavior on touch devices. However, this generally means that the scroll of the page can't be initiated from the draggable element. This is fine if your page isn't meant to be scrolled or if your draggable element is relatively small, but in case of large draggable areas this might become a usability issue.

`preventScroll` is a convenient way to have both vertical drag and vertical scrolling coexist. Note that scroll will always have precedence over drag. To drag vertically the user will have to press and hold the draggable area for `250ms` (or the specified duration) without moving. After this duration, the element is draggable and scrolling is prevented. Note that if you drag horizontally the scroll will immediately be prevented without waiting for this duration.

<Code id="PreventScroll" />

On desktop, you should be able to drag the torus as you would expect without delay. On mobile, initiating scroll from the torus should let you scroll the page as expected. Hold down on the torus and you should be able to drag it after `250ms`. This might be clunky as it's still under testing.

### preventScrollAxis

<Specs gestures={['drag']} types={['x', 'y', 'xy']} defaultValue="y" />

This can optionally be used together with `preventScroll`. This defines the axis/axes in which scrolling is permitted, unless the user taps and holds on the element for the specified duration. Afterwhich, all scrolling is blocked. Depending on the complexity of the nesting of the element, you may need to assign the property `touch-action: pan-x`, `touch-action: pan-y`, or both, to the element to allow for the correct behavior.

### rubberband

<Specs types={['boolean', 'number', 'vector']} defaultValue="[0,0]" />

In some cases, you may want to simulate resistance when the user drags a component, for example when the end of a content is reached[^4].

[^4]: Have a look at [this article](https://medium.com/@nathangitter/building-fluid-interfaces-ios-swift-9732bb934bf5) for more details about building mobile interfaces.

<Code id="Rubberband" disableOverlay />

You can set `rubberband` to `true` to use the default elasticity coeffecient of `0.15`, or specify your own. The `rubberband` option also accepts a vector if you want to set different elasticity coeffecients per axis.

```jsx highlight={3-6}
function RubberbandExample() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ down, offset: [ox, oy] }) => api.start({ x: ox, y: oy, immediate: down }), {
    bounds: { left: -100, right: 100, top: -50, bottom: 50 },
    rubberband: true
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

Note that you have to set [`bounds`](#bounds) for rubberbanding to take effect.

> If you stop your gesture while being off-bounds, **the `offset` or `movement` for the last event will be reverted to the closest bounds**.

### scaleBounds

<Specs
  types={['scaleBounds: { min?: number, max?: number }', '(gestureState) => scaleBounds']}
  defaultValue="{ min: -Infinity, max: Infinity }"
/>

See also [`angleBounds`](#anglebounds).

### swipe.distance

<Specs gestures={['drag']} types={['number', 'vector']} defaultValue="[50,50]" />

See the [`swipe`](/docs/state/#swipe) state attribute for more.

### swipe.duration

<Specs gestures={['drag']} types="number" defaultValue="250" />

A drag gesture lasting more than `swipe.duration` (in milliseconds) will never be considered a swipe. See the [`swipe`](/docs/state/#swipe) state attribute for more.

### swipe.velocity

<Specs gestures={['drag']} types={['number', 'vector']} defaultValue="[0.5,0.5]" />

See the [`swipe`](/docs/state/#swipe) state attribute for more.

### tapsThreshold

<Specs gestures={['drag']} types={['number']} defaultValue="3" />

When using the [filterTaps](#filterTaps) option, taps are only triggered when the displacement is inferior to `3` pixels. You can customize that value by using `tapsThreshold`.

### target (React only)

<Specs types={['node', 'Ref']} defaultValue="undefined" />

> In <UseGesture pkg="vanilla" />, you need to attach a target to the gesture as its first argument. Therefore this options is irrelevant.

&zwnj;<UseGesture pkg="react" /> supports adding handlers to dom nodes directly (or the <code>window</code> or <code>document</code> objects). In that case, you shouldn't spread the <code>bind()</code> object returned by the
hooks as a prop. Cleaning is handled automatically.

```jsx highlight={5-6}
function ScrollExample() {
  const [{ width }, api] = useSpring(() => ({ width: '0%' }))
  const height = document.documentElement.scrollHeight

  useScroll(({ xy: [, y] }) => api.start({ width: (y / height) * 100 + '%' }), { target: window })
  return <animated.div style={{ width }} />
}
```

The code above binds the `scroll` gesture to the document `window`, and acts as a scroll indicator. Try scrolling the page and you'll see the blue bar progress.

<Code id="Target" disableOverlay />

You can also directly pass a ref to `target`. This is actually usefull when you want your events **not to be passive**.

```jsx
const myRef = React.useRef(null)
// This will add a scroll listener the div
useScroll(({ event }) => event.preventDefault(), {
  target: myRef,
  eventOptions: { passive: false }
})

return <div ref={myRef} />
```

### threshold

<Specs types={['vector', 'number']} defaultValue="[0,0]" />

By default, your gesture handler will be triggered as soon as an event is fired. However, there are situations where you want to make sure the user action is **intentional**: that's where `threshold` comes into play.

`threshold` is the minimum displacement the gesture movement needs to travel before your handler is fired.

<Code id="Threshold" />

In this example, we've set the `threshold` to `100`[^2] and made visible when that threshold is exceeded: when you start dragging the blue square, you'll see a ghost square showing how many pixels are left until the blue square starts moving per axis[^3].

[^2]: This is a bit extreme in actual use cases you would be closer to `20`.
[^3]: As you might have noticed from the example above, `threshold` works **per axis**: if the gesture exceeds the threshold value horizontally, you will get updates for horizontal displacement, but vertical threshold will have to be reached before vertical displacement is registered.

```jsx highlight={3-5}
function ThresholdExample() {
  const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ offset: [x, y] }) => api.start({ x, y }), {
    threshold: 10
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> If you still want your handler to be triggered for non intentional displacement, this is where the `triggerAllEvents` config option and the `intentional` state attribute become useful.

### transform

<Specs types="(xy: Vector2) => Vector2" defaultValue="undefined" />

When you're interacting with canvas objects, you're dealing with space coordinates that aren't measured in pixels. In that case, you can tell <UseGesture /> to map screen values to the space with a `transform` function.

<Code id="Transform" />

As you can see from the example below, we use the `transform` function to map the screen coordinates to THREE coordinates. Note that `bounds` or `from` values are expected to be expressed in the new space coordinates. Only `threshold` always refers to screen pixel values.

```jsx highlight={6-11}
function Box() {
  const { viewport } = useThree()
  const { width, height, factor } = viewport
  const [spring, setSpring] = useSpring(() => ({ position: [0, 0, 0], scale: [1, 1, 1] }))

  const bind = useDrag(({ offset: [x, y] }) => setSpring({ position: [x, y, 0] }), {
    // bounds are expressed in canvas coordinates!
    bounds: { left: -width / 2, right: width / 2, top: -height / 2, bottom: height / 2 },
    rubberband: true,
    transform: ([x, y]) => [x / factor, -y / factor]
  })

  return (
    <a3f.mesh {...bind()} {...spring}>
      <boxBufferGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="orange" />
    </a3f.mesh>
  )
}
function Transform() {
  return (
    <Canvas>
      <ambientLight intensity={0.5} />
      <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
      <Box />
    </Canvas>
  )
}
```

> When you use the `useGesture` hook, you can set the `transform` option at the shared level and at the gesture level, with the `transform` set at the gesture level overriding the shared one.

```js
useGesture({/* handlers */ }, {
  transform: ([x, y]) => [x/2, y/2 ] // shared transform applies to all gestures
  pinch: {
    transform: xy => xy // specific pinch transform overrides shared
  }
})
```

### triggerAllEvents

<Specs types="boolean" defaultValue="false" />

Forces the handler to fire even for non intentional displacement (ignores the `threshold`). In that case, the `intentional` attribute from state will remain `false` until the threshold is reached.

> At this point, this option will not work as expected when using `preventScroll` or `preventScrollAxis`. Please flag an issue if this breaks your usecase.

### window

<Specs types="node" defaultValue="window" />

Lets you specify which window element the gesture should bind events to (only relevant for the `drag` gesture).
